﻿//TakeProfitStopLossStrategy.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Strategies
{
	using System;
	using System.Linq;

	using Ecng.Common;
	using Ecng.Collections;

	using StockSharp.BusinessEntities;

	/// <summary>
	/// Стратегия, защищающая сделки одновременно стратегиями <see cref="TakeProfitStrategy"/> и <see cref="StopLossStrategy"/>.
	/// </summary>
	public class TakeProfitStopLossStrategy : BasketStrategy, IProtectiveStrategy
	{
		private readonly object _syncToken = new object();

		/// <summary>
		/// Создать <see cref="TakeProfitStopLossStrategy"/>
		/// </summary>
		/// <param name="takeProfit">Стратегия защиты прибыли.</param>
		/// <param name="stopLoss">Стратегия защиты убытка.</param>
		public TakeProfitStopLossStrategy(TakeProfitStrategy takeProfit, StopLossStrategy stopLoss)
			: base(BasketStrategyFinishModes.First)
		{
			if (takeProfit == null)
				throw new ArgumentNullException("takeProfit");

			if (stopLoss == null)
				throw new ArgumentNullException("stopLoss");

			if (takeProfit.Trade != stopLoss.Trade)
				throw new ArgumentException("Тейк-профит и стоп-лосс стратегии ассоциированы с разными сделками.");

			Trade = takeProfit.Trade;

			ApplyRule(takeProfit, stopLoss);
			ApplyRule(stopLoss, takeProfit);
		}

		private void ApplyRule(ProtectiveStrategy main, ProtectiveStrategy opposite)
		{
			main
				.WhenPositionChanged()
				.Do(() =>
				{
					if (main.LeftVolume == 0)
						opposite.Stop();
					else
						opposite.QuotingVolume = main.LeftVolume;
				})
				.Sync(_syncToken)
				.Apply(this);

			ChildStrategies.Add(main);
		}

		/// <summary>
		/// Защищаемый объем.
		/// </summary>
		public decimal ProtectiveVolume
		{
			get { return ((IProtectiveStrategy)ChildStrategies.First()).ProtectiveVolume; }
			set
			{
				ChildStrategies.OfType<IProtectiveStrategy>().ForEach(s => s.ProtectiveVolume = value);
				ProtectiveVolumeChanged.SafeInvoke();
			}
		}

		/// <summary>
		/// Событие об изменении защищаемого объема.
		/// </summary>
		public event Action ProtectiveVolumeChanged;

		/// <summary>
		/// Защищаемая позиция.
		/// </summary>
		public MyTrade Trade { get; private set; }
	}
}